/* eslint-disable @typescript-eslint/no-explicit-any */
/*
 * @Description: 模板打印（利用Vue模板字符串，可配置）
 * @Author: HuiSir<https://gitee.com/huisir001>
 * @Date: 2025-09-23 09:17:37
 * @LastEditTime: 2025-10-15 17:11:55
 */
import {
  createApp,
  markRaw,
  nextTick,
  defineComponent,
  DefineComponent,
  ComponentPropsOptions,
  ComponentOptionsMixin,
} from "vue";

/**
 * 打印参数
 */
export interface PrintOptions {
  /**
   * 纸张尺寸（预设值："A4" | "A5" | "S60x80" 或自定义尺寸字符串）
   */
  size?: "A4" | "A5" | "S60x80" | string;
  /**
   * 页面方向（portrait/landscape）
   */
  orientation?: "portrait" | "landscape";
  /**
   * 页边距（单位mm）
   */
  margin?: number; // 页边距（单位mm）
}

/**
 * 传参对象
 */
export interface TplPrintOptions {
  /**
   * Vue模板组件路径
   */
  component: DefineComponent<
    ComponentPropsOptions,
    any,
    any,
    any,
    any,
    ComponentOptionsMixin,
    ComponentOptionsMixin,
    any,
    string,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any
  >;
  /**
   * 传参
   */
  props: Record<string, any>;
  /**
   * 打印配置参数
   */
  printOptions?: PrintOptions;
}

/**
 * 模板打印工具函数
 * @param options 打印配置参数
 * @returns Promise<void>
 */
export async function tplPrint(options: TplPrintOptions): Promise<void> {
  const { component, props, printOptions = {} } = options;

  let printFrame: HTMLIFrameElement | null = null;
  let tempAppContainer: HTMLDivElement | null = null;

  try {
    // 创建Vue应用容器
    tempAppContainer = document.createElement("div");

    // 使用vue运行时编译方式
    // 这里需要配置vite的alias，将vue指向vue运行时编译版本,如下
    // resolve: {
    // 路径缩写
    // alias: {
    //   vue: "vue/dist/vue.esm-bundler.js",
    // }
    // }
    const PrintComponent = defineComponent({
      data() {
        // 确保数据不被响应式转换
        return { props: markRaw({ ...props }) };
      },
      template: `<TplComp v-bind="props"/>`,
      components: { TplComp: component },
    });

    // 创建Vue应用
    const app = createApp(PrintComponent);

    // 挂载应用
    app.mount(tempAppContainer);

    // 等待组件渲染完成
    await nextTick();

    // 提取渲染内容
    const content = tempAppContainer.innerHTML;

    // 收集页面样式
    const styles = Array.from(
      document.querySelectorAll('style, link[rel="stylesheet"]')
    )
      .map((el) => el.outerHTML)
      .join("");

    // 卸载应用
    app.unmount();

    // 创建打印专用iframe
    printFrame = document.createElement("iframe");
    printFrame.style.display = "none";
    document.body.appendChild(printFrame);

    // 生成打印样式
    const printStyle = generatePrintStyle(printOptions);

    // 检查iframe是否正常
    if (!printFrame.contentDocument) {
      throw new Error("无法访问打印框架的文档对象");
    }

    // 注入内容到iframe
    printFrame.contentDocument.open();
    printFrame.contentDocument.write(`
      <!DOCTYPE html>
      <html>
        <head>
          <meta charset="UTF-8">
          ${printStyle}
          ${styles}
        </head>
        <body id="print-body">
          ${content}
        </body>
      </html>
    `);
    printFrame.contentDocument.close();

    // 执行打印
    await new Promise<void>((resolve, reject) => {
      if (!printFrame || !printFrame.contentWindow) {
        return reject(new Error("无法访问打印框架的窗口对象"));
      }

      // 等待iframe加载完成
      const handleLoad = () => {
        try {
          printFrame?.contentWindow?.print();
          // 等待打印对话框关闭后解析
          setTimeout(() => resolve(), 1000);
        } catch (error) {
          reject(error);
        } finally {
          // 移除事件监听
          printFrame?.contentWindow?.removeEventListener("load", handleLoad);
        }
      };

      // 如果iframe已经加载完成（可能发生在本地调试时）
      if (printFrame.contentWindow.document.readyState === "complete") {
        handleLoad();
      } else {
        printFrame.contentWindow.addEventListener("load", handleLoad);
      }
    });
  } catch (error) {
    console.error("打印失败:", error);
    throw error;
  } finally {
    // 清理资源
    if (tempAppContainer && tempAppContainer.parentNode) {
      tempAppContainer.parentNode.removeChild(tempAppContainer);
    }

    if (printFrame && printFrame.parentNode) {
      printFrame.parentNode.removeChild(printFrame);
    }
  }
}

/**
 * 生成打印样式（打印一般使用mm单位）
 * @param {Object} PrintOptions
 */
function generatePrintStyle({
  size = "A4",
  orientation = "portrait",
  margin = 10,
}: PrintOptions) {
  /**
   * 纸张尺寸（预设值："A4" | "A5" | "S60x80" 或自定义尺寸字符串）
   */
  const sizeMap: Record<NonNullable<PrintOptions["size"]>, string> = {
    A4: "210mm 297mm",
    A5: "148mm 210mm",
    S60x80: "60mm 80mm",
  };

  /**
   * 若未预设，则使用自定义尺寸（例如传入：'100mm 200mm'）
   */
  const pageSize = sizeMap[size] || size;
  const marginValue = `${margin}mm`;

  return `
    <style>
      @page {
        size: ${pageSize} ${orientation};
        /* 页边距 */
        margin: ${marginValue};
        padding: 0;
        margin-header: 0;
        margin-footer: 0;
      }
      body#print-body {
        /* 使用calc计算宽度，留出适当边距避免右边框被裁剪 */
        width: calc(100% - 1mm);
        margin: 0 auto;
        padding: 0;
        font-family: SimHei, "黑体", sans-serif;
        font-size: 12px;
        color: #000;
      }
      /* 自动分页控制 */
      #print-body .page-break::before {
        content: "";
        display: block;
        page-break-after: always;
        height:0;
        overflow:hidden;
      }
      /* 表格样式处理 */
      #print-body table { 
        page-break-inside: auto;
        border-collapse: collapse;
        border-spacing: 0 !important;
        box-sizing: border-box;
        /* 确保表格不被缩放 */
        transform: scale(1);
        transform-origin: 0 0;
      }
      #print-body th {
        background-color: #f2f2f2;
        font-weight: bold;
        border: 1px solid #000;
      }
      #print-body tr,
      #print-body td {
        page-break-inside: avoid;
        page-break-after: auto;
        border: 1px solid #000;
        /* 确保单元格内容不溢出 */
        box-sizing: border-box;
      }
      /* 确保内容区域宽度正确计算 */
      #print-body {
        box-sizing: border-box;
        overflow: visible;
      }
    </style>
  `;
}

// 保持向后兼容
export default tplPrint;
